package com.hulman.oms.web;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.hulman.oms.bean.Workbench;
import com.hulman.oms.bean.*;
import com.hulman.oms.exception.IoTException;
import com.hulman.oms.service.*;
import com.hulman.oms.shiro.JwtToken;
import com.hulman.oms.util.*;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author: maxwellens
 */
@RestController
public class UserController
{
    @Autowired
    private UserService userService;
    @Autowired
    private WorkbenchService workbenchService;
    @Autowired
    private MenuService menuService;
    @Autowired
    private TeamService teamService;
    @Autowired
    private MiniProgramService miniProgramService;
    @Autowired
    private ContactService contactService;
    @Autowired
    private HttpServletResponse response;

    /**
     * 根据姓名自动生成账号
     *
     * @param text
     * @return
     */
    @PostMapping("/users/pinyin")
    public Result getPinyin(String text)
    {
        String yinpin = StringUtil.getPinyin(text);
        return new Result(yinpin);
    }

    @GetMapping("/users/{id}")
    public Result findUserById(@PathVariable Integer id)
    {
        return new Result(userService.findUserById(id));
    }

    @GetMapping("/users/{id}/toggle-state")
    public Result toggleUserState(@PathVariable Integer id)
    {
        userService.toggleState(id);
        return Result.SUCCESS;
    }

    @GetMapping("/users/{id}/workbenches")
    public Result findUserAppWorks(@PathVariable Integer id)
    {
        List<Workbench> workbenches = workbenchService.findOwnedTreeWorkbenches(id);
        return new Result(workbenches);
    }

    @GetMapping("/users")
    public Result findUsers(Integer page, Integer limit, String keyword, Integer roleId, Integer signState)
    {
        Map<String, Object> map = new HashMap<>();
        map.put("page", page);
        map.put("limit", limit);
        map.put("keyword", keyword);
        map.put("roleId", roleId);
        map.put("signState", signState);
        return userService.findUsersResult(map);
    }

    @GetMapping("/users/roleIds/{roleIds}")
    public Result findUsersByRoleIds(@PathVariable String roleIds)
    {
        List<User> users = userService.findUsersByRoleIds(roleIds);
        return new Result(users);
    }

    @RequestMapping("/users/index")
    public Result findUsersIndex(Integer teamId, String roleIds)
    {
        Map<String, List<String>> map = new HashMap();
        List<User> users;
        if (teamId != null)
        {
            users = teamService.findMembersByTeamId(teamId);
        }
        else if (!StringUtil.isEmpty(roleIds))
        {
            users = userService.findUsersByRoleIds(roleIds);
        }
        else
        {
            users = userService.findAllUsers();
        }
        //通讯录格式处理
        for (User user : users)
        {
            String letter = StringUtil.getPinyinFirstLetters(user.getName().substring(0, 1));
            if (!map.containsKey(letter))
            {
                map.put(letter, new ArrayList<>());
            }
            map.get(letter).add(user.getName());
        }
        List<Object> result = new ArrayList<>();
        for (Map.Entry<String, List<String>> entry : map.entrySet())
        {
            Map<String, Object> item = new HashMap<>();
            item.put("letter", entry.getKey());
            item.put("data", entry.getValue());
            result.add(item);
        }
        return new Result(result);
    }

    @GetMapping("/users/{id}/sync-wework")
    public Result syncWework(@PathVariable Integer id)
    {
        User user = userService.findUserById(id);
        if (user != null)
        {
            Integer userId = user.getId();
            try
            {
                contactService.syncContact(user.getAccount(), user.getName(), user.getMobile(), user.getRoleNames());
                userService.changeSync(userId, 1);
            }
            catch (Exception ex)
            {
                userService.changeSync(userId, 2);
                throw ex;
            }
        }
        return Result.SUCCESS;
    }

    @PostMapping("/users/batch-sync-wework")
    public Result syncWework(String ids)
    {
        if (StringUtil.isEmpty(ids))
        {
            throw new IoTException("请选择用户");
        }
        int[] userIds = NumberUtil.parseIntArray(ids);
        for (int userId : userIds)
        {
            User user = userService.findUserById(userId);
            if (user != null)
            {
                try
                {
                    contactService.syncContact(user.getAccount(), user.getName(), user.getMobile(), user.getRoleNames());
                    userService.changeSync(userId, 1);
                }
                catch (Exception ex)
                {
                    userService.changeSync(userId, 2);
                }
            }
        }
        return Result.SUCCESS;
    }

    @DeleteMapping("/users/{ids}")
    public Result deleteUserById(@PathVariable String ids)
    {
        int[] idArrays = NumberUtil.parseIntArray(ids);
        for (Integer id : idArrays)
        {
            userService.deleteUserById(id);
        }
        return Result.SUCCESS;
    }

    @PutMapping("/users")
    public Result saveUser(User user)
    {
        userService.saveUser(user);
        return Result.SUCCESS;
    }

    /**
     * 当前登录用户
     *
     * @return
     */
    @GetMapping("/users/current")
    public Result getCurrentUser()
    {
        return new Result(SubjectUtil.getUser());
    }

    /**
     * 当前登录用户菜单
     *
     * @return
     */
    @GetMapping("/users/current/menus")
    public Result getCurrentUserMenus()
    {
        User user = SubjectUtil.getUser();
        if (user != null)
        {
            List<Menu> menus = menuService.findOwnedTreeMenus(user.getId());
            return new Result(menus);
        }
        else
        {
            throw new IoTException("用户未登录");
        }
    }

    /**
     * 用户登录
     *
     * @param loginName
     * @param password
     * @return
     */
    @PostMapping("/users/login")
    public Result login(String loginName, String password)
    {
        return jwtLogin(loginName, password);
    }

    /**
     * jwt(JSON Web Token)登录
     *
     * @param loginName
     * @param password
     * @return
     */
    @PostMapping("/users/jwt-login")
    public Result jwtLogin(String loginName, String password)
    {
        User user = userService.findUserByLoginName(loginName);
        if (user != null)
        {
            String account = user.getAccount();
            String encodedPassword = CipherUtil.encrypt(account, password);
            String token = JwtUtil.sign(account, encodedPassword);
            Subject subject = SecurityUtils.getSubject();
            try
            {
                subject.login(new JwtToken(token));
            }
            catch (AuthenticationException ex)
            {
                return new Result(Result.CODE_UNAUTHORIZED, "用户名不存在，或密码不正确", null);
            }
            Team team = teamService.findTeamByUser(user);
            if (team != null)
            {
                user.setTeamId(team.getId());
                user.setTeamName(team.getName());
            }
            Map<String, Object> map = new HashMap<>();
            map.put("user", user);
            map.put("token", token);
            //设置Cookie
            Cookie cookie = new Cookie(JwtToken.NAME, token);
            cookie.setHttpOnly(true);
            cookie.setMaxAge(-1);
            cookie.setPath("/");
            response.addCookie(cookie);
            return new Result(Result.CODE_SUCCESS, "登录成功", map);
        }
        else
        {
            return new Result(Result.CODE_UNAUTHORIZED, "用户名不存在，或密码不正确", null);
        }
    }

    @PostMapping("/users/scan-login")
    public Result scanLogin(String token)
    {
        String username = JwtUtil.getUsername(token);
        //boolean success = JWTUtil.verify(token, username, token);
        //暂不验证
        boolean success = true;
        if (success)
        {
            User user = userService.findUserByAccount(username);
            if (user != null)
            {
                Team team = teamService.findTeamByUser(user);
                if (team != null)
                {
                    user.setTeamId(team.getId());
                    user.setTeamName(team.getName());
                }
                Map<String, Object> map = new HashMap<>();
                map.put("user", user);
                map.put("token", token);
                return new Result(Result.CODE_SUCCESS, "登录成功", map);
            }
            else
            {
                return new Result(Result.CODE_UNAUTHORIZED, "企业微信用户不在系统人员中，请联系管理员添加", null);
            }
        }
        else
        {
            return new Result(Result.CODE_UNAUTHORIZED, "该登录码无效或已经过期", null);
        }
    }

    /**
     * 刷新登录，换取新的JWT
     *
     * @return
     */
    @GetMapping("/users/jwt-refresh")
    public Result jwtRefresh()
    {
        Subject subject = SecurityUtils.getSubject();
        if (subject.isAuthenticated())
        {
            User user = SubjectUtil.getUser();
            String jwt = JwtUtil.sign(user.getAccount(), user.getPassword());
            Map<String, Object> map = new HashMap<>();
            map.put("user", user);
            map.put("token", jwt);
            return new Result(0, "登录成功", map);
        }
        else
        {
            return new Result(-1, "认证失败，请重新登录", null);
        }
    }

    @PostMapping("/users/we-work-login")
    public Result weWorkLogin(String code)
    {
        String account = miniProgramService.code2Session(code);
        if (!StringUtil.isEmpty(account))
        {
            User user = userService.findUserByAccount(account);
            if (user != null)
            {
                String token = JwtUtil.sign(account, user.getPassword());
                Team team = teamService.findTeamByUser(user);
                if (team != null)
                {
                    user.setTeamId(team.getId());
                    user.setTeamName(team.getName());
                }
                Map<String, Object> map = new HashMap<>();
                map.put("user", user);
                map.put("token", token);
                return new Result(Result.CODE_SUCCESS, "登录成功", map);
            }
            else
            {
                return new Result(Result.CODE_UNAUTHORIZED, "该企业微信用户不在系统人员信息中，请联系管理员", null);
            }
        }
        else
        {
            return new Result(Result.CODE_UNAUTHORIZED, "企业微信登录失败", null);
        }
    }

    /**
     * 用户注销
     *
     * @return
     */
    @GetMapping("/users/logout")
    public Result logout()
    {
        Subject subject = SecurityUtils.getSubject();
        if (subject.isAuthenticated())
        {
            subject.logout();
            //设置Cookie
            Cookie cookie = new Cookie(JwtToken.NAME, "");
            cookie.setHttpOnly(true);
            cookie.setMaxAge(0);
            cookie.setPath("/");
            response.addCookie(cookie);
            return new Result(0, "注销成功", null);
        }
        else
        {
            return new Result(0, "用户未登录", null);
        }
    }

    /**
     * 重置密码
     *
     * @return
     */
    @GetMapping("/users/{id}/reset-password")
    public Result resetPassword(@PathVariable Integer id)
    {
        userService.resetPassword(id);
        return Result.SUCCESS;
    }

    @GetMapping("/users/reset-all-password")
    public Result resetAllPassword()
    {
        List<User> users = userService.findAllUsers();
        for (User user : users)
        {
            userService.resetPassword(user.getId());
        }
        return Result.SUCCESS;
    }

    /**
     * 修改密码
     *
     * @param oldPassword 原密码
     * @param newPassword 新密码
     * @param rePassword  重复新密码
     * @return
     */
    @PostMapping("/users/change-password")
    public Result changePassword(String oldPassword, String newPassword, String rePassword)
    {
        if (StringUtils.isEmpty(oldPassword))
        {
            return new Result(1, "原密码不能为空", null);
        }
        if (StringUtils.isEmpty(newPassword))
        {
            return new Result(1, "新密码不能为空", null);
        }
        if (StringUtils.isEmpty(rePassword))
        {
            return new Result(1, "新密码重复不能为空", null);
        }
        if (oldPassword.length() < 6 || newPassword.length() < 6 || rePassword.length() < 6)
        {
            return new Result(1, "密码长度至少六位", null);
        }
        if (!newPassword.equals(rePassword))
        {
            return new Result(1, "新密码和确认密码不一致", null);
        }
        if (SubjectUtil.getUser() == null)
        {
            return new Result(1, "未登录，请重新登录系统", null);
        }
        String account = SubjectUtil.getUser().getAccount();
        User user = userService.findUserByAccount(account);
        String encryptedOldPassword = CipherUtil.encrypt(user.getAccount(), oldPassword);
        if (!encryptedOldPassword.equals(user.getPassword()))
        {
            return new Result(1, "原密码不正确", null);
        }
        userService.changePassword(user.getId(), newPassword);
        String encryptedNewPassword = CipherUtil.encrypt(user.getAccount(), newPassword);
        String jwt = JwtUtil.sign(account, encryptedNewPassword);
        return new Result(jwt);
    }

    @PostMapping("/users/import")
    public Result importUsers(MultipartFile file) throws IOException
    {
        File tmp = new File(System.getProperty("java.io.tmpdir") + "/" + System.currentTimeMillis() + ".xlsx");
        file.transferTo(tmp);
        try
        {
            List<User> users = EasyExcel.read(tmp).head(User.class).sheet(0).doReadSync();
            for (User user : users)
            {
                User checkUser = userService.findUserByName(user.getName());
                if (checkUser == null)
                {
                    userService.saveUser(user);
                }
            }
            return Result.SUCCESS;
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
            return new Result(ex.getMessage(), null);
        }
    }

    /**
     * 获取当前值班长
     *
     * @return
     */
    @GetMapping("/users/shift-leader")
    public Result findShiftLeader()
    {
        User user = userService.findShiftLeader();
        return new Result(user);
    }

    /**
     * 成为值班长
     *
     * @param id
     * @return
     */
    @PostMapping("/users/shift-leader")
    public Result takeShiftLeader()
    {
        Subject subject = SecurityUtils.getSubject();
        if (subject.isAuthenticated())
        {
            User user = SubjectUtil.getUser();
            userService.takeShiftLeader(user.getId());
            return Result.SUCCESS;
        }
        else
        {
            return new Result(-1, "认证失败，请重新登录", null);
        }
    }

    @GetMapping("/users/export")
    public void exportUsers(String keyword, Integer roleId, Boolean onDuty) throws IOException
    {
        response.setContentType("multipart/form-data");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename=users.xlsx");

        Map<String, Object> map = new HashMap<>();
        map.put("keyword", keyword);
        map.put("roleId", roleId);
        if (onDuty != null && onDuty)
        {
            map.put("attendanceState", 1);
        }
        List<User> users = userService.findUsers(map);
        ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build();
        WriteSheet sheet0 = EasyExcel.writerSheet(0, "人员").head(User.class).build();
        excelWriter.write(users, sheet0);
        excelWriter.finish();
    }

}
